using System;
using Com.ContentRendering.Api.ParserEngine;
using ContentRenderingApi.Node;
using System.Text;
using System.Diagnostics;

namespace ContentRenderingApi.Envelope
{
    /// <summary/>
    internal class OutputNodeEnvelope : OutputNodeInterface
    {
        private Action<int, string> _logger;
        private AbstractNode _node;

        /// <summary/>
        internal OutputNodeEnvelope(
            Action<int, string> logger,
            AbstractNode node)
        {
            this._logger = logger;
            this._node = node;
        }

        /// <summary/>
        private void Log(string unparsedLines)
        {
            // was a logger provided
            if (this._logger == null)
            {
                return;
            }

            // write the log
            this._logger(this.FetchLevel(), unparsedLines);
        }

        /// <summary/>
        private int FetchLevel()
        {
            int level = 0;

            AbstractNode node = this._node;

            while (node != null)
            {
                // move to the parent
                node = node.Parent;

                // increment the level
                level++;
            }

            return level;
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddParentSubstitutionTag(int level)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_PARENT_SUBSTITUTION_TAG, level));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddParentSubstitutionTag(level));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddParentTransparentTag(int level)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_PARENT_TRANSPARENT_TAG, level));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddParentTransparentTag(level));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddParentIfTag(int level)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_PARENT_IF_TAG, level));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddParentIfTag(level));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddParentIfNotTag(int level)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_PARENT_IF_NOT_TAG, level));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddParentIfNotTag(level));
        }

        /// <summary/>
        void OutputNodeInterface.AddParentOutputTag(int level)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_PARENT_OUTPUT_TAG, level));

            // create the node
            this._node.AddParentOutputTag(level);
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddChildSubstitutionTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_CHILD_SUBSTITUTION_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddChildSubstitutionTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddChildTransparentTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_CHILD_TRANSPARENT_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddChildTransparentTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddChildIfTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_CHILD_IF_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddChildIfTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddChildIfNotTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_CHILD_IF_NOT_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddChildIfNotTag(name));
        }

        /// <summary/>
        void OutputNodeInterface.AddChildOutputTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_CHILD_OUTPUT_TAG, name));

            // create the node
            this._node.AddChildOutputTag(name);
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddRootSubstitutionTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_ROOT_SUBSTITUTION_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddRootSubstitutionTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddRootTransparentTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_ROOT_TRANSPARENT_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddRootTransparentTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddRootIfTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_ROOT_IF_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddRootIfTag(name));
        }

        /// <summary/>
        OutputNodeInterface OutputNodeInterface.AddRootIfNotTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_ROOT_IF_NOT_TAG, name));

            // create the node
            return new OutputNodeEnvelope(this._logger, _node.AddRootIfNotTag(name));
        }

        /// <summary/>
        void OutputNodeInterface.AddRootOutputTag(string name)
        {
            // log the action
            this.Log(string.Format(Constant.FORMAT_ADD_ROOT_OUTPUT_TAG, name));

            // create the node
            this._node.AddRootOutputTag(name);
        }

        /// <summary/>
        void OutputNodeInterface.AddContent(string content)
        {
            // log the action
            this.Log(content);

            // create the node
            this._node.AddContent(content);
        }
        
        /// <summary/>
        OutputNodeInterface OutputNodeInterface.Parent
        {
            get
            {
                // make sure the parent is not null ... don't wrap null objects
                if (this._node.Parent == null)
                {
                    return null;
                }

                return new OutputNodeEnvelope(this._logger, this._node.Parent);
            }
        }
    }
}
